/*
Copyright 2016 S7connector members (github.com/s7connector)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.mt.roll.opcua.s7.my.s7connector.impl.nodave;

import com.mt.roll.opcua.s7.my.s7connector.api.DaveArea;
import com.mt.roll.opcua.s7.my.s7connector.type.PlcVar;
import com.mt.roll.opcua.s7.my.s7connector.type.TransportSize;

public final class PDU {
	/**
	 * known function codes
	 */
	public final static byte FUNC_READ = 4;

	public final static byte FUNC_WRITE = 5;

	public int data;

	int dlen;
	int error;

	int header; // the position of the header;
	int hlen;
	byte[] mem;       //msgOut 也就是 上位机==》plc 的channel
	public int param; // the position of the parameters;
	public int plen;
	public int udata;
	public int udlen;

	/**
	 * set up the PDU information
	 *
	 * mem  =》  msgOut、msgIn
	 * pos  =》  pdu在整个request请求 的起始位置（起始都是7，第7个字节）
	 */
	public PDU(final byte[] mem, final int pos) {
		this.mem = mem;
		this.header = pos;
	}

	public int addBitVarToReadRequest(final int area, final int DBnum, final int start, final int len) {
		final byte pa[] = { 0x12, 0x0a, 0x10, 0x01, /* single bits */
				0x00, 0x1A, /* insert length in bytes here */
				0x00, 0x0B, /* insert DB number here */
				(byte) 0x84, /* change this to real area code */
				0x00, 0x00, (byte) 0xC0 /* insert start address in bits */
		};
		Nodave.setUSBEWord(pa, 4, len);
		Nodave.setUSBEWord(pa, 6, DBnum);
		Nodave.setUSBELong(pa, 8, start);
		Nodave.setUSByte(pa, 8, area);

		this.mem[this.param + 1]++;
		System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
		this.plen += pa.length;
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		return 0;

	}

	public void addBitVarToWriteRequest(final DaveArea area, final int DBnum, final int start, final int byteCount,
			final byte[] buffer) {
		final byte da[] = { 0, 3, 0, 0, };
		final byte pa[] = { 0x12, 0x0a, 0x10, 0x01, /* single bit */
				0, 0, /* insert length in bytes here */
				0, 0, /* insert DB number here */
				0, /* change this to real area code */
				0, 0, 0 /* insert start address in bits */
		};
		if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
				|| (area == DaveArea.COUNTER200)) {
			pa[3] = (byte) area.getCode();
			pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
			pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
		} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
			pa[3] = 4;
			pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
			pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
		} else {
			pa[4] = (byte) (byteCount / 0x100);
			pa[5] = (byte) (byteCount & 0xff);
		}
		pa[6] = (byte) (DBnum / 256);
		pa[7] = (byte) (DBnum & 0xff);
		pa[8] = (byte) area.getCode();
		pa[11] = (byte) (start & 0xff);
		pa[10] = (byte) ((start / 0x100) & 0xff);
		pa[9] = (byte) (start / 0x10000);

		if ((this.dlen % 2) != 0) {
			this.addData(da, 1);
		}

		this.mem[this.param + 1]++;
		if (this.dlen > 0) {
			final byte[] saveData = new byte[this.dlen];
			System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
			System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
		}
		System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
		this.plen += pa.length;
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		this.data = this.param + this.plen;

		this.addData(da);
		this.addValue(buffer);
	}

	/**
	 * Add data after parameters, set dlen as needed. Needs valid header and
	 * parameters
	 */
	void addData(final byte[] newData) {
		final int appPos = this.data + this.dlen; // append to this position
		this.dlen += newData.length;
		System.arraycopy(newData, 0, this.mem, appPos, newData.length);
		Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
	}

	/**
	 * Add len bytes of len after parameters from a maybe longer block of bytes.
	 * Set dlen as needed. Needs valid header and parameters
	 */
	public void addData(final byte[] newData, final int len) {
		final int appPos = this.data + this.dlen; // append to this position
		this.dlen += len;
		System.arraycopy(newData, 0, this.mem, appPos, len);
		Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
	}

	public void addParam(final byte[] pa) {
		this.plen = pa.length;
		System.arraycopy(pa, 0, this.mem, this.param, this.plen);
		//设置S7-Header 里的Parameter Length
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		// mem[header + 6] = (byte) (pa.length / 256);
		// mem[header + 7] = (byte) (pa.length % 256);
		//this.data = 17+2 = 19 ( data 其实就是item项 )
		this.data = this.param + this.plen;
		this.dlen = 0;
	}

	/*
	 * add data in user data. Add a user data header, if not yet present.
	 */
	public void addUserData(final byte[] da) {
		final byte udh[] = { (byte) 0xff, 9, 0, 0 };
		if (this.dlen == 0) {
			this.addData(udh);
		}
		this.addValue(da);
	}

	/**
	 * Add values after value header in data, adjust dlen and data count. Needs
	 * valid header,parameters,data,dlen
	 */
	void addValue(final byte[] values) {
		int valCount = (0x100 * this.mem[this.data + 2]) + this.mem[this.data + 3];

		if (this.mem[this.data + 1] == 4) { // bit data, length is in bits
			valCount += 8 * values.length;
		} else if (this.mem[this.data + 1] == 9) { // byte data, length is in
													// bytes
			valCount += values.length;
		} else if(this.mem[this.data+1] == 3){
			// for bool
			valCount += values.length;


		}else {
			// for other
		}
		if (this.udata == 0) {
			this.udata = this.data + 4;
		}


		this.udlen += values.length;
		Nodave.setUSBEWord(this.mem, this.data + 2, valCount);
		this.addData(values);
	}

	public int addVarToReadRequest(final DaveArea area, final int DBnum, int start, final int len) {
		final byte[] pa = {
				0x12,   		//结构表示，一般默认 0x12
				0x0a,			//此字节往后的字节数
				0x10,			//Syntax id:S7ANY (0X10) （决定寻址方式，0x10表示any-type）
				0x02, 			//Transport size  数据类型  ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的，后续自己修改吧。
				0x00, 0x1A,     /* length of data in bytes ( 2 bytes )，就是读几个长度 如有些变量是数组 ，这里就是数组长度，如果是非数组变量那么这里都是1 */
				0x00, 0x0B,     /* DB块编号 */
				(byte) 0x84,    // * area code ，也就是 DaveArea.DB数据区 */
				0x00, 0x00, (byte) 0xC0 /* 0-2bit 是Bit Address，3-18bit 是Byte Address */
		};

		if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
			pa[3] = 4;
			start *= 8; /* bits */
		} else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
				|| (area == DaveArea.COUNTER200)) {
			pa[3] = (byte) area.getCode();
		} else {
			start *= 8; /* 乘以8  相当于把这个偏移量向左移动了 3位 */
		}
		//把len =》 2个字节  并且填充到 pa数组  对应位置（pa[4]、pa[5]）。
		Nodave.setUSBEWord(pa, 4, len);
		Nodave.setUSBEWord(pa, 6, DBnum);
		//start 是这个db块的偏移量。。。。        //todo 其实这里简单处理了 ，是分Byte address 和 Bit address的
		Nodave.setUSBELong(pa, 8, start);
		Nodave.setUSByte(pa, 8, area.getCode());

		//因为add了 Var 所以要 ,item count ++ ；；this.param + 1 位置就是Item count位置
		this.mem[this.param + 1]++;

		//把 构建好的 param(Var Item) 加入到 Read Request 字节流里面去。
		System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
		this.plen += pa.length;
		//要读的 var item 也算 参数的 所以也算在param length里面。
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		/**
		 * TODO calc length of result. Do not add variable if it would exceed
		 * max. result length.
		 */
		return 0;
	}
	public int addVarToReadRequest(final DaveArea area, final int DBnum, int byteAddress,int bitAddress, final int len,final TransportSize transportSize) {
		final byte[] pa = {
				0x12,   		//结构表示，一般默认 0x12
				0x0a,			//此字节往后的字节数
				0x10,			//Syntax id:S7ANY (0X10) （决定寻址方式，0x10表示any-type）(把这个认为是固定就行了)
				0x02, 			//Transport size  数据类型  ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的，后续自己修改吧。
				0x00, 0x1A,     /* length of data in bytes ( 2 bytes )，就是读几个长度 如有些变量是数组 ，这里就是数组长度，如果是非数组变量那么这里都是1 */
				0x00, 0x0B,     /* DB块编号 */
				(byte) 0x84,    // * area code ，也就是 DaveArea.DB数据区 */
				0x00, 0x00, (byte) 0xC0 /* 0-2bit 是Bit Address，3-18bit 是Byte Address */
		};

		if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
			pa[3] = 4;
			byteAddress *= 8; /* bits */
		} else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
				|| (area == DaveArea.COUNTER200)) {
			pa[3] = (byte) area.getCode();
		} else {
			///* 乘以8  相当于把这个偏移量向左移动了 3位,,向左移动3位的原因是为了 给bitAddress 让路 */
			byteAddress *= 8;
			//把 bitAddress 赋予后三位
			byteAddress += bitAddress;
		}
		pa[3] = Byte.valueOf(Short.toString(transportSize.getCode()));

		//把len =》 2个字节  并且填充到 pa数组  对应位置（pa[4]、pa[5]）。
		Nodave.setUSBEWord(pa, 4, len);
		Nodave.setUSBEWord(pa, 6, DBnum);
		//start 是这个db块的偏移量。。。。        //todo 其实这里简单处理了 ，是分Byte address 和 Bit address的
		Nodave.setUSBELong(pa, 8, byteAddress);
		Nodave.setUSByte(pa, 8, area.getCode());

		//因为add了 Var 所以要 ,item count ++ ；；this.param + 1 位置就是Item count位置
		this.mem[this.param + 1]++;

		//把 构建好的 param(Var Item) 加入到 Read Request 字节流里面去。
		System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
		this.plen += pa.length;
		//要读的 var item 也算 参数的 所以也算在param length里面。
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		/**
		 * TODO calc length of result. Do not add variable if it would exceed
		 * max. result length.
		 */
		return 0;
	}


	public void addVarToWriteRequest(final DaveArea area, final int DBnum, int byteOffset, int bitOffset, final int byteCount,
									 final byte[] buffer, PlcVar var) {
		final byte da[] = { 0, 4, 0, 0, };
		final byte pa[] = {
				0x12,
				0x0a,
				0x10,
				0x02,       //Transport size  数据类型  ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的，后续自己修改吧。
				/* unit (for count?, for consistency?) byte */
				0, 0, /* length in bytes */
				0, 0, /* DB number */
				0, /* area code */
				0, 0, 0 /* start address in bits */
		};
		if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
				|| (area == DaveArea.COUNTER200)) {
			pa[3] = (byte) area.getCode();
			pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
			pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
		} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
			pa[3] = 4;
			pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
			pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
		} else {
			pa[4] = (byte) (byteCount / 0x100);
			pa[5] = (byte) (byteCount & 0xff);
		}
		pa[6] = (byte) (DBnum / 256);
		pa[7] = (byte) (DBnum & 0xff);
		pa[8] = (byte) (area.getCode());

		//设置parameter item 的 transportsize
		pa[3] = (byte) var.getTransportSize().getCode();

		///* 乘以8  相当于把这个偏移量向左移动了 3位,,向左移动3位的原因是为了 给bitAddress 让路 */
		byteOffset *= 8;
		//把 bitAddress 赋予后三位
		byteOffset += bitOffset;
		pa[11] = (byte) (byteOffset & 0xff);
		pa[10] = (byte) ((byteOffset / 0x100) & 0xff);
		pa[9] = (byte) (byteOffset / 0x10000);
		if ((this.dlen % 2) != 0) {
			this.addData(da, 1);
		}
		this.mem[this.param + 1]++;
		if (this.dlen > 0) {
			final byte[] saveData = new byte[this.dlen];
			System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
			System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
		}
		System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
		this.plen += pa.length;
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		this.data = this.param + this.plen;
		this.addData(da);
		//给 keyItem 的transportsize 赋值
		this.mem[this.data + 1] = (byte) var.getTransportSize().getDataTransportSize().getValue();
		this.addValue(buffer);
	}

	public void addVarToWriteRequest(final DaveArea area, final int DBnum, int start, final int byteCount,
			final byte[] buffer) {
		final byte da[] = { 0, 4, 0, 0, };
		final byte pa[] = { 0x12, 0x0a, 0x10, 0x02,
				/* unit (for count?, for consistency?) byte */
				0, 0, /* length in bytes */
				0, 0, /* DB number */
				0, /* area code */
				0, 0, 0 /* start address in bits */
		};
		if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
				|| (area == DaveArea.COUNTER200)) {
			pa[3] = (byte) area.getCode();
			pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
			pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
		} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
			pa[3] = 4;
			pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
			pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
		} else {
			pa[4] = (byte) (byteCount / 0x100);
			pa[5] = (byte) (byteCount & 0xff);
		}
		pa[6] = (byte) (DBnum / 256);
		pa[7] = (byte) (DBnum & 0xff);
		pa[8] = (byte) (area.getCode());
		start *= 8; /* number of bits */
		pa[11] = (byte) (start & 0xff);
		pa[10] = (byte) ((start / 0x100) & 0xff);
		pa[9] = (byte) (start / 0x10000);
		if ((this.dlen % 2) != 0) {
			this.addData(da, 1);
		}
		this.mem[this.param + 1]++;
		if (this.dlen > 0) {
			final byte[] saveData = new byte[this.dlen];
			System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
			System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
		}
		System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
		this.plen += pa.length;
		Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
		this.data = this.param + this.plen;

		//下面两个方法，是拼接 keyItem、valueItem
		this.addData(da);

		this.addValue(buffer);
	}

	/**
	 * construct a write request for a single item in PLC memory.
	 */
	/*
	 * void constructWriteRequest( int area, int DBnum, int start, int len,
	 * byte[] buffer) { byte pa[] = new byte[14]; byte da[] = { 0, 4, 0, 0 };
	 * pa[0] = PDU.FUNC_WRITE; pa[1] = (byte) 0x01; pa[2] = (byte) 0x12; pa[3] =
	 * (byte) 0x0a; pa[4] = (byte) 0x10; pa[5] = (byte) 0x02;
	 *
	 * Nodave.setUSBEWord(pa, 6, len); Nodave.setUSBEWord(pa, 8, DBnum);
	 * Nodave.setUSBELong(pa, 10, 8 * start); // the bit address
	 * Nodave.setUSByte(pa, 10, area); initHeader(1); addParam(pa); addData(da);
	 * addValue(buffer); if ((Nodave.Debug & Nodave.DEBUG_PDU) != 0) { dump(); }
	 * }
	 */
	/**
	 * display information about a PDU
	 */
	public void dump() {
		Nodave.dump("PDU header ", this.mem, this.header, this.hlen);
		System.out.println("plen: " + this.plen + " dlen: " + this.dlen);
		Nodave.dump("Parameter", this.mem, this.param, this.plen);
		if (this.dlen > 0) {
			Nodave.dump("Data     ", this.mem, this.data, this.dlen);
		}
		if (this.udlen > 0) {
			Nodave.dump("result Data ", this.mem, this.udata, this.udlen);
		}
	}

	public int getError() {
		return this.error;
	}

	/**
	 * return the function code of the PDU
	 */
	public int getFunc() {
		return Nodave.USByte(this.mem, this.param + 0);
	}

	/*
	 * typedef struct { uc P; // allways 0x32 uc type; // a type? type 2 and 3
	 * headers are two bytes longer. uc a,b; // currently unknown us number; //
	 * Number, can be used to identify answers corresponding to requests us
	 * plen; // length of parameters which follow this header us dlen; // length
	 * of data which follows the parameters uc x[2]; // only present in type 2
	 * and 3 headers. This may contain error information. } PDUHeader;
	 */
	/**
	 * return the number of the PDU
	 */
	public int getNumber() {
		return Nodave.USBEWord(this.mem, this.header + 4);
	}

	/**
	 * reserve space for the header of a new PDU
	 */
	public void initHeader(final int type) {
		//注意 这里的type 就是下面的 MSG Type（消息类型）
		if ((type == 2) || (type == 3)) {
			this.hlen = 12;
		} else {
			this.hlen = 10;
		}

		//给S7-Header 初始化    全部初始化为0
		for (int i = 0; i < this.hlen; i++) {
			//mem 代表msgOut
			this.mem[this.header + i] = 0;
		}

		//this.param 是 param的起始位置，是在 initHeader 被初始化的，（7+10） = 17= this.param (因为数组从0开始，所以17这个位置刚好是param的起始位置)
		this.param = this.header + this.hlen;
		//protocol id 协议id ，默认0x32
		this.mem[this.header] = (byte) 0x32;
		//MSG Type（1byte）: 消息类型 :
		//0x01：工作请求（Job Request）;
		//0x02：确认（Ack），主要是由设备请求，不携带数据;
		//0x03：响应数据（Ack-Data），响应0x01的请求;
		//0x07：自定义数据（Userdata），扩展协议类型
		this.mem[this.header + 1] = (byte) type;
		//dlen = data length ( 报文中存在两个字节 )
		this.dlen = 0;
		//plen = param length ( 报文中存在两个字节 )
		this.plen = 0;
		//udlen = protocol data unit reference length
		this.udlen = 0;
		this.data = 0;
		//udata = protocol data unit reference
		this.udata = 0;
	}

	public void initReadRequest() {
		final byte pa[] = new byte[2];
		pa[0] = PDU.FUNC_READ;
		pa[1] = (byte) 0x00;
		this.initHeader(1);
		this.addParam(pa);
	}

	/**
	 * prepare a read request with no item.
	 */
	public void prepareReadRequest() {
		final byte pa[] = new byte[2];
		pa[0] = PDU.FUNC_READ;
		pa[1] = (byte) 0x00;
		this.initHeader(1);
		this.addParam(pa);
	}

	/**
	 * prepare a write request with no item.
	 */
	public void prepareWriteRequest() {
		final byte pa[] = new byte[2];
		pa[0] = PDU.FUNC_WRITE;
		pa[1] = (byte) 0x00;
		this.initHeader(1);
		this.addParam(pa);
	}

	/**
	 * set the number of the PDU
	 */
	public void setNumber(final int n) {
		Nodave.setUSBEWord(this.mem, this.header + 4, n);
	}

	/**
	 * Setup a PDU instance to reflect the structure of data present in the
	 * memory area given to initHeader. Needs valid header.
	 */

	public int setupReceivedPDU() {
		int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
		//this.mem[this.header + 1]( ROSCTR ) 就是MSG TYPE =2 (确认（Ack），主要是由设备请求，不携带数据) ;;MSG TYPE =3 (响应数据（Ack-Data），响应0x01的请求)
		if ((this.mem[this.header + 1] == 2) || (this.mem[this.header + 1] == 3)) {
			this.hlen = 12;
			//this.header + 10 就是 Error class（看附录3）/code（看附录4）
			//todo this.header + 10 其实是一个字节一个字节的 不能像下面这样读两个字节。（其实这种也行的，因为这样就能够 同时判断两个信息 是否同时为0，如果同时为0 有一个不为0 就代表都不ok）
			res = Nodave.USBEWord(this.mem, this.header + 10);
		} else {
			this.error = 0;
			this.hlen = 10;
			res = 0;
		}
		//外部初始化的  header == 7（4字节TPKT + 3个字节COTP）
		//this.param = 7+12 = 19;
		this.param = this.header + this.hlen;
		//读取S7-Header 里面的Param-length（2个字节转为word   ok）
		this.plen = Nodave.USBEWord(this.mem, this.header + 6);
		//this.param(19 固定的如果是ACK) + this.plen(2 是固定的应为就两个参数)
		this.data = this.param + this.plen;

		//读取S7-Header 里面的Data-length（2个字节转为word   ok）
		this.dlen = Nodave.USBEWord(this.mem, this.header + 8);
		this.udlen = 0;
		this.udata = 0;
		return res;
	}


	int testResultData() {
		int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
		//当响应成功的情况  //todo here read
		if ((this.mem[this.data] == (byte) 255) && (this.dlen > 4)) {
			res = Nodave.RESULT_OK;
			//udata 代表的是read response 里面 Data=>Item=>n个字节的实际数据bytes
			this.udata = this.data + 4;
			// udlen=data[2]*0x100+data[3];
			//udlen = udata length 就是实际承载value 的byte[] 长度
			this.udlen = Nodave.USBEWord(this.mem, this.data + 2);

			// ==4 是走byte流，通过转义字节来 来解码真是value。。   看附录8
			if (this.mem[this.data + 1] == 4) {
				//注意 这里的数据响应长度  单位 是bit 不是 byte，因为 用bit 表示才准确，比如像bit类型  他并不需要一个字节
				//往右移3位，就相当于 除以8 ，把 bit 转成 byte   //todo 这个需要和read request关联的，后续如果要开发点位的功能 再说。
				this.udlen >>= 3; /* len is in bits, adjust */
			} else if (this.mem[this.data + 1] == 9) {
				/* len is already in bytes, ok */
			} else if (this.mem[this.data + 1] == 3) {
				/* len is in bits, but there is a byte per result bit, ok */
			} else {
				res = Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE;
			}
		} else {
			//当响应不成功的情况
			//this.mem[this.data]   是return code  （成功或者失败）
			res = this.mem[this.data];
		}
		return res;
	}

	public int testPGReadResult() {
		if (this.mem[this.param] != 0) {
			return Nodave.RESULT_UNEXPECTED_FUNC;
		}
		return this.testResultData();
	};

	int testReadResult() {
		if (this.mem[this.param] != FUNC_READ) {
			return Nodave.RESULT_UNEXPECTED_FUNC;
		}
		return this.testResultData();
	}

	int testWriteResult() {
		int res = Nodave.RESULT_CANNOT_EVALUATE_PDU;
		if (this.mem[this.param] != FUNC_WRITE) {
			return Nodave.RESULT_UNEXPECTED_FUNC;
		}
		if ((this.mem[this.data] == 255)) {
			res = Nodave.RESULT_OK;
		} else {
			res = this.mem[this.data];
		}
		return res;
	}

}
